package com.iot08.common.service.base;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.BasicDBObject;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.json.JsonWriterSettings;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import javax.annotation.Resource;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.List;

/**
 * @version 1.0
 * @Description: service基类(iot08), 部分基本查询的封装
 * @time: 2020/11/11 17:08
 * @author: Rock
 */
@Slf4j
public class BaseService<T> {

    @Resource(name = "appMongoTemplate")
    protected MongoTemplate mongoTemplate;

    /*********************************** 实体类 ******************************/

    /**
     * 获取泛型类的class
     *
     * @time: 2020/11/11 17:35
     * @author: Rock
     * @version 1.0
     */
    protected Class<T> getTClass() {
        return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    /**
     * @time: 2020/12/24 17:50
     * @author: Rock
     * @version 1.0
     */
    protected MongoCollection<Document> getCollection() {
        return mongoTemplate.getCollection(mongoTemplate.getCollectionName(getTClass()));
    }

    /**
     * 根据_id获取数据（单条记录）
     *
     * @param id
     * @time: 2020/11/11 17:39
     * @author: Rock
     * @version 1.0
     */
    public T findById(Object id) {
        return mongoTemplate.findById(id, getTClass());
    }

    /**
     * 保存
     *
     * @param entity
     * @time: 2020/11/11 17:50
     * @author: Rock
     * @version 1.0
     */
    public T save(T entity) {
        return mongoTemplate.save(entity);
    }

    public List<String> findDistinct(String field) {
        return mongoTemplate.findDistinct(field, getTClass(), String.class);
    }


    /**
     * 根据_id更新数据（单个）
     *
     * @param id
     * @param update
     * @time: 2020/11/11 17:36
     * @author: Rock
     * @version 1.0
     */
    public void updateById(Object id, Update update) {
        if (update.getUpdateObject().isEmpty()) {
            log.warn("Update is Empty. id={}. getTClass={}", id, getTClass());
        } else {
            mongoTemplate.updateFirst(new Query(Criteria.where("_id").is(id)), update, getTClass());
        }
    }

    /**
     * 根据_id更新数据（多个）
     *
     * @param ids
     * @param update
     * @time: 2020/12/11 10:33
     * @author: Rock
     * @version 1.0
     */
    public void updateByIds(Collection<?> ids, Update update) {
        if (update.getUpdateObject().isEmpty()) {
            log.warn("Update is Empty. ids={}. getTClass={}", ids, getTClass());
        } else {
            mongoTemplate.updateMulti(new Query(Criteria.where("_id").in(ids)), update, getTClass());
        }
    }

    /**
     * @param query
     * @param update
     * @time: 2021/3/24 14:42
     * @author: Rock
     * @version 1.0
     */
    public void update(Query query, Update update) {
        if (update.getUpdateObject().isEmpty()) {
            log.warn("Update is Empty. query={}. getTClass={}", query, getTClass());
        } else {
            mongoTemplate.updateFirst(query, update, getTClass());
        }
    }

    /**
     * 根据_id删除（单条）
     *
     * @param id
     * @time: 2020/11/11 17:59
     * @author: Rock
     * @version 1.0
     */
    public boolean delById(Object id) {
        DeleteResult result = mongoTemplate.remove(new Query(Criteria.where("_id").is(id)), getTClass());
        if (result != null) {
            return result.getDeletedCount() > 0;
        }
        return false;
    }

    /**
     * 根据_id删除记录（多条，传入的参数为id列表）
     *
     * @param ids
     * @time: 2020/11/20 14:31
     * @author: Rock
     * @version 1.0
     */
    public long delByIds(Collection<?> ids) {
        DeleteResult result = mongoTemplate.remove(new Query(Criteria.where("_id").in(ids)), getTClass());
        if (result != null) {
            return result.getDeletedCount();
        }
        return 0l;
    }

    /**
     * 根据条件删除
     *
     * @param query
     * @time: 2021/1/9 17:32
     * @author: Rock
     * @version 1.0
     */
    public long delByQuery(Query query) {
        DeleteResult result = mongoTemplate.remove(query, getTClass());
        if (result != null) {
            return result.getDeletedCount();
        }
        return 0l;
    }

    /**
     * 根据_id获取记录列表（传入参数为id列表）
     *
     * @param ids
     * @time: 2020/11/13 14:54
     * @author: Rock
     * @version 1.0
     */
    public List<T> listByIds(Collection<?> ids) {
        return mongoTemplate.find(new Query(Criteria.where("_id").in(ids)), getTClass());
    }

    /**
     * 根据条件查找单个记录
     *
     * @param query
     * @time: 2020/12/1 15:15
     * @author: Rock
     * @version 1.0
     */
    public T findOne(Query query) {
        return mongoTemplate.findOne(query, getTClass());
    }

    /**
     * 根据条件查找多个记录
     *
     * @param query
     * @time: 2020/12/1 15:16
     * @author: Rock
     * @version 1.0
     */
    public List<T> find(Query query) {
        return mongoTemplate.find(query, getTClass());
    }

    /**
     * 根据条件查询记录总数量
     *
     * @param query
     * @time: 2021/1/4 15:13
     * @author: Rock
     * @version 1.0
     */
    public long count(Query query) {
        return mongoTemplate.count(query, getTClass());
    }


    /*********************************** Document文档查找 ******************************/

    /**
     * 按id 更新文档
     *
     * @param doc
     * @time: 2021/6/19 18:09
     * @author: weichao
     * @version 1.0
     */
    public boolean updateDoc(String id, Document doc) {
        Bson bson = Filters.eq("_id", id);
        return getCollection().updateOne(bson, doc).wasAcknowledged();
    }

    /**
     * 添加文档
     *
     * @param doc
     * @time: 2021/1/25 10:09
     * @author: Rock
     * @version 1.0
     */
    public boolean insertOneDoc(Document doc) {
        return getCollection().insertOne(doc).wasAcknowledged();
    }

    /**
     * 按id查找单个文档
     *
     * @param id
     * @time: 2020/12/24 18:09
     * @author: Rock
     * @version 1.0
     */
    public Document findDocById(Object id) {
        Bson bson = Filters.eq("_id", id);
        return getCollection().find(bson).limit(1).first();
    }

    /**
     * 按id查找文档列表
     *
     * @param ids
     * @time: 2020/12/24 18:11
     * @author: Rock
     * @version 1.0
     */
    public FindIterable<Document> listDocByIds(Collection<?> ids) {
        Bson bson = Filters.in("_id", ids);
        return getCollection().find(bson);
    }

    /**
     * @param query
     * @param sort
     * @param num
     * @time: 2020/12/28 14:24
     * @author: Rock
     * @version 1.0
     */
    public FindIterable<Document> findDoc(Bson query, Bson sort, int page, int num) {
        if (num == -1) {
            return getCollection().find(query).sort(sort);
        } else {
            return getCollection().find(query).sort(sort).skip(page * num).limit(num);
        }
    }

    public <T> T toBean(BasicDBObject dbObject, Class<T> clzss){

        String realJson = dbObject.toJson(JsonWriterSettings.builder().build());

        T obj = JSON.parseObject(realJson,clzss);

        return obj;

    }

    public <T> T toBean(Document document,Class<T> clzss){

        String realJson = document.toJson(JsonWriterSettings.builder().build());

        T obj = JSONObject.parseObject(realJson,clzss);

        return obj;

    }

    public static <T> BasicDBObject toDBObject(T object){

        String json = JSON.toJSONString(object);

        BasicDBObject basicDBObject = BasicDBObject.parse(json);

        return basicDBObject;

    }

    public static <T> Document toDocument(T object){

        String json = JSON.toJSONString(object);

        Document document = Document.parse(json);

        return document;

    }

}
